using System;
using System.Collections.Generic;
using System.Text;

namespace RapidHDL
{
    public class ExternalInterfaceComponent : Component 
    {
        TopLevelComponent oTopLevel;
        ExternalSignalInterface oExternalSignalInterface;

        public NodeVector ClockIn;
        public NodeVector ResetIn;
        public NodeVector StartIn;
        public NodeVector WriteIn;
        public NodeVector WriteAddressIn;
        public NodeVector ReadAddressIn;

        public NodeVector DataIn;
        public NodeVector DataOut;

        /*public NodeVector RamAddr;
        public NodeVector RamDOut;
        public NodeVector RamDIn;
        public NodeVector RamBusy;
        public NodeVector RamStart;
        public NodeVector RamWrite;*/

        public NodeVector TestBusWrite;
        public NodeVector TestBusRead;

        public NodeVector FIFOIn;
        public NodeVector FIFOOut;
        public NodeVector FIFOWrite;
        public NodeVector FIFORead;
        public NodeVector FIFOStatus;

        public NodeVector RamIn;
        public NodeVector RamOut;
        public NodeVector RamWrite;
        public NodeVector RamRead;
        public NodeVector RamStatus;


        //RapidHardware RapidHardware; to remove warning

        public ExternalInterfaceComponent(TopLevelComponent poTopLevelComponent)
            : base (poTopLevelComponent.RapidHardware,"external_interface")
        {
            oTopLevel = poTopLevelComponent;
        }

        /// <summary>
        /// Moved from constructor, so it is called after the setting have been set
        /// </summary>
        public void IntitializeExternalSignalInterface(int piReadAddressWidth, int piWriteAddressWidth, int piInputWidth, int piOutputWidth)
        {
            Components.Add("top_level_component", oTopLevel);
            oTopLevel.AttachExternalInteface(this);
            iHirarchyLevel = 0;

            ClockIn = this.CreateNodeVector("MAIN_CLK_I", 1);


            ResetIn = this.CreateNodeVector("MAIN_RESET_I", 1);
            ResetIn.ForcedNodeStructure = NetStructure.Input;

            StartIn = this.CreateNodeVector("MAIN_START_I", 1);
            WriteIn = this.CreateNodeVector("MAIN_WRITE_I", 1);
            DataIn = this.CreateNodeVector("MAIN_DATA_I", piInputWidth);
            ReadAddressIn = this.CreateNodeVector("MAIN_READ_ADDR_I", piReadAddressWidth);
            WriteAddressIn = this.CreateNodeVector("MAIN_WRITE_ADDR_I", piWriteAddressWidth);
            DataOut = this.CreateNodeVector("MAIN_DATA_O", piOutputWidth);

            TestBusRead = this.CreateNodeVector("TEST_BUS_READ_I", 13);
            TestBusRead.ForcedNodeStructure = NetStructure.Input;

            TestBusWrite = this.CreateNodeVector("TEST_BUS_WRITE_O", 13);
            TestBusWrite.ForcedNodeStructure = NetStructure.Output;

            FIFOIn = this.CreateNodeVector("FIFO_I", 18, NodeFlowType.Source);
            FIFOIn.ForcedNodeStructure = NetStructure.Input;
            FIFOStatus = this.CreateNodeVector("FIFO_STATUS_I", 2, NodeFlowType.Source);
            FIFOStatus.ForcedNodeStructure = NetStructure.Input;
            FIFOOut = this.CreateNodeVector("FIFO_O", 16);
            FIFOOut.ForcedNodeStructure = NetStructure.Output;
            FIFORead = this.CreateNodeVector("FIFO_READ_O", 1);
            FIFORead.ForcedNodeStructure = NetStructure.Output;
            FIFOWrite = this.CreateNodeVector("FIFO_WRITE_O", 1);
            FIFOWrite.ForcedNodeStructure = NetStructure.Output;
            
            RamIn = this.CreateNodeVector("RAM_I", 48, NodeFlowType.Source);
            RamIn.ForcedNodeStructure = NetStructure.Input;
            RamStatus = this.CreateNodeVector("RAM_STATUS_I", 4, NodeFlowType.Source);
            RamStatus.ForcedNodeStructure = NetStructure.Input;
            RamOut = this.CreateNodeVector("RAM_O", 64);
            RamOut.ForcedNodeStructure = NetStructure.Output;
            RamRead = this.CreateNodeVector("RAM_READ_O", 1);
            RamRead.ForcedNodeStructure = NetStructure.Output;
            RamWrite = this.CreateNodeVector("RAM_WRITE_O", 1);
            RamWrite.ForcedNodeStructure = NetStructure.Output;
            
            oExternalSignalInterface = new ExternalSignalInterface(this, "signal_interface", piWriteAddressWidth, piReadAddressWidth, piInputWidth, piOutputWidth);

            oExternalSignalInterface.ResetIn.Connection = ResetIn;
            
            oExternalSignalInterface.ClockIn.Connection = ClockIn;
            oExternalSignalInterface.StartIn.Connection = StartIn;
            oExternalSignalInterface.WriteIn.Connection = WriteIn;
            oExternalSignalInterface.DataIn.Connection = DataIn;
            oExternalSignalInterface.DataOut.Connection = DataOut;
            oExternalSignalInterface.ReadAddressIn.Connection = ReadAddressIn;
            oExternalSignalInterface.WriteAddressIn.Connection = WriteAddressIn;
        }

        public void GenerateExternalSignalInterface()
        {
            /*if (RapidHardware.Settings.UseSDRAM)
            {
                RamAddr = this.CreateNodeVector("RAM_ADDR_O", RapidHardware.Settings.SDRAMAddressBits);
                RamAddr.ForcedNodeStructure = NodeStructure.Output;
                RamWrite = this.CreateNodeVector("RAM_WRITE_O", 1);
                RamWrite.ForcedNodeStructure = NodeStructure.Output;
                RamStart = this.CreateNodeVector("RAM_START_O", 1);
                RamStart.ForcedNodeStructure = NodeStructure.Output; 
                RamBusy = this.CreateNodeVector("RAM_BUSY_I", 1, NodeFlowType.Source);
                RamBusy.ForcedNodeStructure = NodeStructure.Input;
                RamDOut = this.CreateNodeVector("RAM_DATA_OUT_I", RapidHardware.Settings.SDRAMDataBits,NodeFlowType.Source);
                RamDOut.ForcedNodeStructure = NodeStructure.Input;
                RamDIn = this.CreateNodeVector("RAM_DATA_IN_O", RapidHardware.Settings.SDRAMDataBits);
                RamDIn.ForcedNodeStructure = NodeStructure.Output;

                RapidHardware.Structure.TopLevelComponent.SDRAMInterface.SysWrite.Connection = RamWrite;
                RapidHardware.Structure.TopLevelComponent.SDRAMInterface.SysStart.Connection = RamStart;
                RapidHardware.Structure.TopLevelComponent.SDRAMInterface.SysBusy.Connection = RamBusy;
                RapidHardware.Structure.TopLevelComponent.SDRAMInterface.SysDataIn.Connection = RamDIn;
                RapidHardware.Structure.TopLevelComponent.SDRAMInterface.SysDataOut.Connection = RamDOut;
                RapidHardware.Structure.TopLevelComponent.SDRAMInterface.SysAddress.Connection = RamAddr;

                RapidHardware.Structure.TopLevelComponent.TestBusRead.Connection = TestBusRead;
                RapidHardware.Structure.TopLevelComponent.TestBusWrite.Connection = TestBusWrite;
            }*/

            if (RapidHardware.Settings.UseTestBus)
            {
                RapidHardware.Structure.TopLevelComponent.TestBusRead.Connection = TestBusRead;
                RapidHardware.Structure.TopLevelComponent.TestBusWrite.Connection = TestBusWrite;
            }
            else
            {
                TestBusWrite.Join(0);
                Utility.SinkExtraBits(this, TestBusRead);
            }

            if (RapidHardware.Settings.UseSDRAM)
            {
                RapidHardware.Structure.TopLevelComponent.SDRAMInterface.OutputFIFOData.Connection = RamOut;
                RapidHardware.Structure.TopLevelComponent.SDRAMInterface.OutputFIFORead.Connection = RamRead;
                RapidHardware.Structure.TopLevelComponent.SDRAMInterface.OutputFIFOWrite.Connection = RamWrite;
                RapidHardware.Structure.TopLevelComponent.SDRAMInterface.InputStatusReg.Connection = RamStatus;
                RapidHardware.Structure.TopLevelComponent.SDRAMInterface.InputFIFOData.Connection = RamIn;
            }
            else
            {
                RamOut.Join(0);
                RamRead.Join(0) ;
                RamWrite.Join(0);
                Utility.SinkExtraBits(this,RamStatus);
                Utility.SinkExtraBits(this,RamIn);
            }

            if (RapidHardware.Settings.UseSDRAM)
            {
                RapidHardware.Structure.TopLevelComponent.FIFOInterface.OutputFIFOData.Connection = FIFOOut;
                RapidHardware.Structure.TopLevelComponent.FIFOInterface.OutputFIFORead.Connection = FIFORead;
                RapidHardware.Structure.TopLevelComponent.FIFOInterface.OutputFIFOWrite.Connection = FIFOWrite;
                RapidHardware.Structure.TopLevelComponent.FIFOInterface.InputStatusReg.Connection = FIFOStatus;
                RapidHardware.Structure.TopLevelComponent.FIFOInterface.InputFIFOData.Connection = FIFOIn;
            }
            else
            {
                FIFOOut.Join(0);
                FIFORead.Join(0);
                FIFOWrite.Join(0);
                Utility.SinkExtraBits(this,FIFOStatus);
                Utility.SinkExtraBits(this,FIFOIn);
            }

            oExternalSignalInterface.BaseGenerateStructure();
            NodeVector oDataOut = new NodeVector(this.RapidHardware.SystemInterface, "data_out_external", DataOut.Nodes.Count);
            oDataOut.Connection = DataOut;

            if (RapidHardware.Structure.TopLevelComponent.MainReset != null)
            {
                RapidHardware.Structure.TopLevelComponent.MainReset.Connection = ResetIn;
            }
        }

        public void ConnectSimulation()
        {
            SignalSource oSource = RapidHardware.SystemInterface.AddSignalSource("MAIN_RESET",1,0);
            oSource.ConnectNodeVector(ResetIn, 0);
            oSource.InterfaceSource = true;

            RapidHardware.SystemInterface.AddSignalSource("MAIN_WRITE_ADDRESS", WriteAddressIn, 0).InterfaceSource = true;
            RapidHardware.SystemInterface.AddSignalSource("MAIN_DATA", DataIn, 0).InterfaceSource = true;
        }

        public void SimulateWrite(int iAddress, int iValue)
        {
            SignalSource srData = RapidHardware.SystemInterface.GetSignalSource("MAIN_DATA");
            SignalSource srAddress = RapidHardware.SystemInterface.GetSignalSource("MAIN_WRITE_ADDRESS");
            ClockSink cWrite = oExternalSignalInterface.WriteClock;

            srAddress.ValueAsInt = iAddress;
            srData.ValueAsInt = iValue;
            cWrite.ToggleClock();
            cWrite.ToggleClock();
        }

        public ExternalSignalInterface ExternalSignalInterface
        {
            get { return oExternalSignalInterface; }
        }
    }
}
